Skip to content

ci: add release-please and conventional commit enforcement#333

Open
gjtorikian wants to merge 4 commits intomainfrom
add-release-please
Open

ci: add release-please and conventional commit enforcement#333
gjtorikian wants to merge 4 commits intomainfrom
add-release-please

Conversation

@gjtorikian
Copy link
Contributor

@gjtorikian gjtorikian commented Mar 4, 2026

Summary

  • Adds release-please to automate versioning, changelog generation, and GitHub releases
  • Replaces the manual version-bump workflow with release-please's automated release PR flow
  • Removes the release.yml workflow (release-please now creates GitHub releases, and Packagist auto-syncs via webhook)
  • Adds a PR title linter (lint-pr-title.yml) to enforce Conventional Commits, which release-please uses to determine version bumps

Follows the same pattern as workos-ruby#435 and workos-node#1467.

How it works

  1. Conventional commits (feat:, fix:, chore:, etc.) are enforced on PR titles via amannn/action-semantic-pull-request
  2. PRs are squash-merged, so the PR title becomes the commit message on main
  3. release-please-action opens (or updates) a release PR with a version bump and CHANGELOG.md entry
  4. Merging the release PR creates a GitHub Release + tag
  5. Packagist auto-detects the new tag via webhook

PHP-specific: keeping lib/Version.php in sync

We use release-type: "php" which handles composer.json and CHANGELOG.md out of the box. However, this SDK also has a lib/Version.php file with a hardcoded SDK_VERSION constant (used for the User-Agent header). The php strategy doesn't know about this file.

The Ruby and Node SDKs use version-file to point release-please at their version files, but that option is only supported by the ruby and simple strategies — it's silently ignored for php.

Instead, we use extra-files with the generic updater. This requires an x-release-please-version annotation comment on the version line in lib/Version.php:

public const SDK_VERSION = '4.30.1'; // x-release-please-version

The generic updater matches the semver string on annotated lines and replaces it with the new version, leaving the rest of the file untouched.

Changes

File Change
.github/workflows/lint-pr-title.yml New — validates PR titles follow conventional commit format
.github/workflows/release-please.yml New — runs on push to main, creates release PRs automatically
.release-please-manifest.json New — tracks current version (4.30.1)
release-please-config.json New — configures release-please for PHP releases, with extra-files generic updater for lib/Version.php
lib/Version.php Modified — added x-release-please-version annotation so release-please can bump SDK_VERSION
.github/workflows/release.yml Removed — no longer needed, release-please creates GitHub releases
.github/workflows/version-bump.yml Removed — no longer needed with release-please

Test plan

  • Verify lint-pr-title check runs on this PR (title uses conventional commit format)
  • After merge, verify release-please creates a release PR on next conventional commit push
  • Consider adding lint-pr-title as a required status check in branch protection for main

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gjtorikian gjtorikian requested a review from a team as a code owner March 4, 2026 18:14
@gjtorikian gjtorikian requested a review from mthadley March 4, 2026 18:14
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 4, 2026

Greptile Summary

This PR replaces the manual version-bump and release workflows with a fully automated release-please pipeline, and adds a PR title linter to enforce conventional commits — a clean, well-structured modernisation of the release process.

Key observations:

  • The version in .release-please-manifest.json (4.30.1) correctly matches lib/Version.php, so the initial release-please state is consistent.
  • release-please-config.json correctly points at lib/Version.php as the version file with the php release type, which release-please knows how to parse and update.
  • lint-pr-title.yml correctly uses pull_request_target (needed so the workflow runs with repo-context permissions for PRs from forks) and restricts permissions to pull-requests: read, which is appropriately scoped.
  • Action pinning regression: The removed workflows (release.yml, version-bump.yml) pinned every third-party action to an immutable commit SHA. Both new workflow files switch to mutable tag references (@v5, @v4, @v2). Given that release-please.yml runs on push to main with contents: write and pull-requests: write permissions, and lint-pr-title.yml runs on pull_request_target with access to GITHUB_TOKEN, restoring SHA pinning is recommended to maintain the same supply-chain security posture.

Confidence Score: 4/5

  • Safe to merge; the only concern is a style-level regression in action-pinning discipline inherited from the removed workflows.
  • The functional changes are correct — version is consistent, config points to the right files, and permissions are appropriately scoped. The sole issue is that both new workflow files use mutable tag references instead of SHA-pinned actions, which lowers supply-chain security compared to what existed before. This is a best-practice concern rather than a blocking bug.
  • .github/workflows/release-please.yml and .github/workflows/lint-pr-title.yml should have their action references pinned to commit SHAs before merging.

Important Files Changed

Filename Overview
.github/workflows/lint-pr-title.yml New workflow to enforce conventional commit format on PR titles using amannn/action-semantic-pull-request; correctly uses pull_request_target for fork PR support, but the action is not pinned to an immutable SHA.
.github/workflows/release-please.yml New release automation workflow using release-please; both actions/create-github-app-token and googleapis/release-please-action use mutable tag references instead of SHA pins, which is a regression from the removed workflows' security posture.
.release-please-manifest.json Manifest correctly tracks the current version 4.30.1, which is consistent with lib/Version.php.
release-please-config.json Release-please config correctly specifies the PHP release type, package name, and version file path; no issues.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Developer opens PR] --> B[lint-pr-title.yml\npull_request_target]
    B --> C{PR title follows\nConventional Commits?}
    C -- No --> D[Check fails\nPR blocked]
    C -- Yes --> E[PR merged to main\nvia squash merge]
    E --> F[release-please.yml\npush to main]
    F --> G[googleapis/release-please-action\nopens or updates Release PR]
    G --> H{Release PR\nmerged?}
    H -- No --> G
    H -- Yes --> I[GitHub Release + tag created\nby release-please]
    I --> J[Packagist detects new tag\nvia webhook]
Loading

Last reviewed commit: 3c7397c

Comment on lines +18 to +23
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
with:
app-id: ${{ vars.SDK_BOT_APP_ID }}
private-key: ${{ secrets.SDK_BOT_PRIVATE_KEY }}

- uses: googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38 # v4.4.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mutable action tags replace SHA-pinned references

The removed workflows (release.yml, version-bump.yml) consistently pinned every third-party action to an immutable commit SHA (e.g., actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf). The new workflows switch to mutable tag references (@v2, @v4), which means a compromised or accidentally-overwritten tag could silently run malicious code with contents: write and pull-requests: write permissions during a push to main.

Pin both actions to their current SHAs to maintain the same security posture as the removed workflows:

Suggested change
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
with:
app-id: ${{ vars.SDK_BOT_APP_ID }}
private-key: ${{ secrets.SDK_BOT_PRIVATE_KEY }}
- uses: googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38 # v4.4.0
- name: Generate token
id: generate-token
uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2
with:
app-id: ${{ vars.SDK_BOT_APP_ID }}
private-key: ${{ secrets.SDK_BOT_PRIVATE_KEY }}
- uses: googleapis/release-please-action@a02a34c4d625b9a4a4de9c2a2a6c5fb5b41b9c0d # v4
with:
token: ${{ steps.generate-token.outputs.token }}

(Replace the example SHAs above with the actual current HEAD SHAs from each action's repository before merging.)

lint:
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@e32d7e603df1aa1ba07e981f2a23455dee596825 # v5
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unpinned action tag

amannn/action-semantic-pull-request@v5 uses a mutable tag, consistent with the regression noted in release-please.yml. Because this workflow runs on pull_request_target (which has access to repository secrets), an attacker who can push to the action's v5 tag could exfiltrate the GITHUB_TOKEN.

Pin to the SHA corresponding to the v5 release:

Suggested change
- uses: amannn/action-semantic-pull-request@e32d7e603df1aa1ba07e981f2a23455dee596825 # v5
- uses: amannn/action-semantic-pull-request@0723387faaf9b38adef4775cd42cfd5155ed6017 # v5

(Replace the example SHA with the actual SHA from the action's repository.)

gjtorikian and others added 2 commits March 4, 2026 13:18
The `version-file` option is only supported by `ruby` and `simple`
strategies — it's silently ignored for `release-type: php`. Use
`extra-files` with the `generic` updater instead, which matches the
`x-release-please-version` annotation comment to find and replace
the semver string.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant